﻿package de.gameduell.framework.facebook.app {
	import de.gameduell.framework.facebook.app.appevents.CoinEventManager;
	import de.gameduell.framework.facebook.app.pyramide.Brick;

	import de.gameduell.facebook.service.gen.CatalogItem;
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.framework.facebook.FBBaseApplicationData;
	import de.gameduell.framework.facebook.FBBaseController;
	import de.gameduell.framework.facebook.GameResult;
	import de.gameduell.framework.facebook.event.InventoryEvent;
	import de.gameduell.framework.facebook.reporting.ReportingEvent;
	import de.gameduell.framework.util.FlashVars;
	import de.gameduell.framework.util.Tools;

	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;

	public class Controller extends FBBaseController {
		private static var instance:Controller;
		
		public static const REPLAY_MISSION:String = "REPLAY_MISSION";
		public static const REGULAR_MISSION:String = "REGULAR_MISSION";
		
		public static var JACKPOT_FEATURE_ID:int = 27;
		public static var AWARDS_FEATURE_ID:int = 35;
		
		private var _gameData:GameData;
		private var _activeTaskId:String;
		private var _coinEventManager:CoinEventManager;
		private var _foreignUserId:String = "";
		private var _xmlMissionList:XMLList;
		private var _brickConditionList:XMLList;

		public static function getInstance():Controller {
			if(instance == null) {
				instance = new Controller();
			}
			return instance;
		}
		
		public function refreshBrowser():void {
			navigateToURL(new URLRequest("http://apps.facebook.com/dragonclick"), "_top"); // TODO - still hardcoded
		}
		
		public function set foreignUserId(anId:String):void {
			_foreignUserId = anId;
		}
		
		public function get foreignUserId():String {
			return _foreignUserId;
		}
		
		public function get xmlMissionList():XMLList {
			return _xmlMissionList;
		}
		
		public function get brickConditionList():XMLList {
			return _brickConditionList;
		}

		public function Controller() {
			super();
			applicationData.jackpot.init(this); // jackpot feature ... TODO - cleanup ? - right location for init?
			
			_gameData = new GameData(gameState, this);
			_gameData.addEventListener(GameData.APP_LIFE_COST_FOUND, resetAndStoreLifeCost);
			_gameData.addEventListener(GameData.APP_COINS_CHANGED, storeCoins);
			_gameData.addEventListener(GameData.APP_LIVES_CHANGED, storeLives);
			_gameData.addEventListener(GameData.APP_PYRAMID_CHANGED, storePyramid);
			_gameData.addEventListener(GameData.APP_LIVES_TIMESTAMP_CHANGED, storeLivesTimeStamp);
			_gameData.addEventListener(GameData.APP_BRICK_INVENTORY_CHANGED, storeUserBrickInventory);
			_gameData.addEventListener(GameData.APP_CLEAN_UP_DONATIONS, onCleanupDonations);

			_inventory.addEventListener(InventoryEvent.INVENTORY_ITEM_ADDED, _gameData.onInventoryItemAdded);

			tracker.customerId = appData.facebookData.userId;
			setupFeedbackConnection();
		}
		
		private function onCleanupDonations(event:Event):void {
			_gameData.removeEventListener(GameData.APP_CLEAN_UP_DONATIONS, onCleanupDonations);
			_communication.requestDeleteGamestates(_gameData.donationStates);
		} 
		
		public function parsePyramid(brickXML:XML):void {
			_xmlMissionList = brickXML.child("missions").children();
			_brickConditionList = brickXML.child("brickConditions").children();
			_gameData.pyramid.setup(_xmlMissionList, _brickConditionList);
		}
				
		public function parseCoinEvents(coinEventXML:XML):void {
			var coinEventList:XMLList = coinEventXML.children();
			if(_coinEventManager == null) {
				_coinEventManager = new CoinEventManager(coinEventList);
			}
		}
		
		public function get coinEventManager():CoinEventManager {
			return _coinEventManager;
		}

		private function storeUserBrickInventory(event:Event = null):void {
			Debug.trace("Controller::storeUserBrickInventory", Debug.DEBUG);
			_communication.requestStoreGamestateByKey(GameData.KEY_BRICK_INVENTORY, gameData.brickInventory.toString());
		}

		private function storePyramid(event:Event = null):void {
			Debug.trace("Controller::storePyramid", Debug.DEBUG);
			_communication.requestStoreGamestateByKey(GameData.KEY_PYRAMID, gameData.pyramid.pyramidToString() );
		}
		
		private function storeCoins(event:Event):void {
			_communication.requestStoreGamestateByKey(GameData.KEY_COINS, String(gameData.coins));
		}
		
		private function resetAndStoreLifeCost(event:Event = null):void {
			_communication.requestStoreGamestateByKey(GameData.KEY_LIFE_COST, "0");
		}

		private function storeLives(event:Event):void {
			if(_gameData.lives >= 0){
				_communication.requestStoreGamestateByKey(GameData.KEY_LIVES, String(gameData.lives));
			}
			if(_gameData.lives == 0){
				if(!_gameIsRunning){
					dispatchEvent(new Event(FBBaseController.OUT_OF_LIVES));
				}
			}
		}
		
		public function get activeTaskId():String {
			return _activeTaskId;
		}

		private function storeLivesTimeStamp(event:Event):void {
			_communication.requestStoreGamestateByKey(GameData.KEY_LIVES_TIMESTAMP, String(gameData.livesTimestamp));
		}
		
		public function removeLife(aCount:String = "1"):void {
			_gameData.lives = _gameData.lives - int(aCount);
			resetAndStoreLifeCost();
		}
		
		public function get gameData():GameData {
			return _gameData;
		}

		public function startTutorial(type:String, width:int, height:int, language:String, divXPos:int, divYPos:int):void {
			tracker.track("start_tutorial");
			setupLocalConnection();
			Debug.trace("Controller::startTutorial: " + type + ":" + width + ":" + height + ":" + language + ":" + connectionKey);
			dispatchEvent(new Event(TUTORIAL_START));
			Tools.callJavaScript("startGame", type, width, height, language, connectionKey, divXPos, divYPos, "", "");
		}
		
		public function closeTutorial(aReason:String):void {
			tracker.track("close_tutorial");
			Debug.trace("Controller::closeTutorial: reason was -> " +  aReason);
			Tools.callJavaScript("closeGame");
			dispatchEvent(new Event(TUTORIAL_FINISHED));
			reportGameEnd("", "0", "", "", "", (aReason == "finished"));
		}
		
		public function buyJackpotGame(jackpotItem:CatalogItem):void {
			if(!_gameIsRunning){
				buyItem(jackpotItem);
			}
		}
		
		override public function startJackpotGame(gameType:String, width:int, height:int, divXPos:int, divYPos:int):void {
			if(!_gameIsRunning){
				_currentGameType = JACKPOT_GAME;
				tracker.track("start_jackpot_game");
				setupLocalConnection();
				Tools.callJavaScript("startGame", ingameType, 760, 558, FlashVars.getKeyValue(FlashVars.LANGUAGE), connectionKey, divXPos, divYPos, "jackpot", "true", "true", "");
				communication.requestStartJackpotGame();
				dispatchEvent(new Event(JACKPOT_GAME_START));
				reportGameStart();
			}
		}

		private function reportGameEnd( gameId:String = "", missionId:String = "", earnedCoins:String = "",
										totalCoins:String = "", score:String = "", isNewHighScore:Boolean = false,
										totalLives:String = "", lifeLost:Boolean = false):void {
			
			var reportingEvent:ReportingEvent = new ReportingEvent(trackingName + "_game_result");
			reportingEvent.addEventField("game_id", gameId);
			reportingEvent.addEventField("mission_id", missionId);
			reportingEvent.addEventField("earned_coins", earnedCoins);
			reportingEvent.addEventField("total_coins", totalCoins);
			reportingEvent.addEventField("score", score);
			reportingEvent.addEventField("is_newhighscore", String(isNewHighScore));
			reportingEvent.addEventField("total_lives", totalLives);
			reportingEvent.addEventField("has_life_lost", String(lifeLost));
			reportApplicationEvent(reportingEvent);
		}
		
		private function reportGameStart(event:Event = null):void {
			var reportingEvent:ReportingEvent = new ReportingEvent(trackingName + "_game_create");
			if(event != null){
				reportingEvent.addEventField("game_id", appData.gameId);
				reportingEvent.addEventField("mission_id", String(_activeTaskId));
			}else{ 
				// is a jackpot game!
				reportingEvent.addEventField("game_id", appData.jackpot.currentJackpotId);
				reportingEvent.addEventField("mission_id", "");
			}
			reportApplicationEvent(reportingEvent);
		}
	
		public function startGameWithId(taskId:String, divXPos:int, divYPos:int, isReplay:Boolean = false):void {
			if(_gameData.lives > 0 && !_gameIsRunning) {
				appData.addEventListener(FBBaseApplicationData.GAMEID_CHANGED, reportGameStart);
				Debug.trace("FBBaseController::startGameWithId: taskId=" + taskId, Debug.DEBUG);
				_gameIsRunning = true;
				_currentGameType = isReplay ? REPLAY_MISSION : REGULAR_MISSION;
				_activeTaskId = taskId;
				tracker.track("start_game");
				communication.requestStartGame();
				Debug.trace("Controller::startGameWithId: TAKING LIFE ...", Debug.DEBUG);
				communication.requestStoreGamestateByKey("life_cost", "1");
				setupLocalConnection();
				Tools.callJavaScript("startGame", ingameType, 760, 558, FlashVars.getKeyValue(FlashVars.LANGUAGE), connectionKey, divXPos, divYPos, taskId, "true", String(isReplay), "");
				dispatchEvent(new Event(GAME_START));
			}else{
				if(_gameData.lives == 0){
					tracker.track("start_game_no_lives");
					dispatchEvent(new Event(FBBaseController.OUT_OF_LIVES));
				}
				if(_gameIsRunning){
					Debug.trace("FBBaseController::startGameWithId: taskId=" + taskId + " GAME IS ALREADY STARTED !!", Debug.WARNING);
				}
			}
		}
		
		override public function registerScore(aResultString:String):void {
			appData.removeEventListener(FBBaseApplicationData.GAMEID_CHANGED, reportGameStart);
			_gameIsRunning = false;
			Tools.callJavaScript("closeGame");
			if(_currentGameType == JACKPOT_GAME){
				updateJackpotScore(aResultString);
			}else{
				tracker.track("end_game");
				Debug.trace("Controller::registerScore: score=" + aResultString, Debug.DEBUG);
				_lastGameResult = new GameResult(aResultString, _activeTaskId);
				localeData.setValue("score", String(_lastGameResult.score));
				
				var currentBrick:Brick = _gameData.pyramid.getBrickByID(_activeTaskId);
				Debug.trace("Controller::registerScore: currentBrick: " + currentBrick + " endReason: " + _lastGameResult.endReason, Debug.DEBUG);
				communication.requestStoreGamestateByKey("life_cost", "0");
				
				if(_lastGameResult.score > currentBrick.score){
					Debug.trace("Controller::registerScore: updating score of brick: " + currentBrick.score + " -> " + _lastGameResult.score, Debug.DEBUG);
					currentBrick.score = _lastGameResult.score;
				}
				var newHighScore:Boolean = true;
				
				if(_gameData.pyramid.totalScore > int(facebookData.user.highscore)){
					Debug.trace("Conroller::registerScore: UPDATING HIGHSCORE: was: " + int(facebookData.user.highscore) + " is now: " + _gameData.pyramid.totalScore);
					facebookData.user.highscore = String(_gameData.pyramid.totalScore);
					localeData.setValue("totalScore", String(_gameData.pyramid.totalScore));
					_communication.requestUpdateScore(_gameData.pyramid.totalScore); // TODO - save always ...
					storePyramid();
					dispatchEvent(new Event(FBBaseController.NEW_HIGHSCORE));
				}else{
					newHighScore = false;
					Debug.trace("Conroller::registerScore: NO NEW HIGHSCORE");
				}
				reportGameEnd(appData.gameId, _activeTaskId,
							  String(_lastGameResult.collectedCoins), String(_gameData.coins + _lastGameResult.collectedCoins),
							  String(_lastGameResult.score), newHighScore,
							  String(_gameData.lives), !_lastGameResult.completed);
								
				dispatchEvent(new Event(GAME_END));
			}
		}
		
		public function checkLives(event:Event = null):void {
			if(_gameData.lives == 0){
				dispatchEvent(new Event(OUT_OF_LIVES));
			}
		}
		
		public function get baseURL():String {
			return _baseURL;
		}
		
		// ########### public callback functions for local connection ##############
		
		/**
		 * not used yet ...
		 */
//		public function buyBoost(boostId:int):void {
//			Debug.trace("Controller::buyBoost: boostId=" + boostId, Debug.DEBUG);
//			var boostItem:CatalogItem = inventory.getItemById(boostId);
//			if(boostItem != null){
//				if(boostItem.price > int(facebookData.balance.balance)){
//					_communication.addEventListener(ServiceLayerCommunication.PURCHASE_ITEM_FAILED, reportPurchaseFailedToClient);
//					_communication.buyItem(boostItem);
//				} else{
//					reportOutOfMoneyToClient();
//				}
//			}
//		}

//		private function reportPurchaseFailedToClient(event:Event):void {
//			Debug.trace("Controller::reportPurchaseFailedToClient", Debug.DEBUG);
//			_communication.removeEventListener(ServiceLayerCommunication.PURCHASE_ITEM_FAILED, reportPurchaseFailedToClient);
//		}

//		private function reportOutOfMoneyToClient(event:Event = null):void {
//			Debug.trace("Controller::reportOutOfMoneyToClient", Debug.DEBUG);
//		}
	}
}